package com.uuah.server.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.CharsetDecoder;

import org.apache.commons.lang.ArrayUtils;
import org.apache.mina.core.buffer.IoBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.server.UuahServer;
import com.uuah.server.api.message.IUuahBusiMessage;
import com.uuah.server.api.message.IUuahBusiMessageCollection;
import com.uuah.server.message.busi.UuahBusiMessage;
import com.uuah.server.message.busi.UuuahBusiMessageCollection;
import com.uuah.utils.UUID;
import com.uuah.utils.UuahUtils;

/**
 *
 * TODO comment ...
 *
 * <p>update record:updator，update time，update content and version</p>
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-4-19 下午06:41:09
 * @version 1.0.0
 */
public class UuahBusiMessageUtils {
	private static Logger logger = LoggerFactory
			.getLogger(UuahBusiMessageUtils.class);

	public static boolean validateUuahBusiMessage(IoBuffer ioBuffer) {
		IoBuffer buffer = ioBuffer.asReadOnlyBuffer();
		int minLength = IUuahBusiMessage.UUAH_BUSI_MESSAGE_BASICVER_LENGTH
				+ IUuahBusiMessage.UUAH_BUSIMESSAGE_CODE_LENGTH
				+ IUuahBusiMessage.UUAH_BUSIMESSAGE_DATALENGTH_LENGTH
				+ IUuahBusiMessage.UUAH_BUSI_MESSAGE_LENGTH_LENGTH
				+ IUuahBusiMessage.UUAH_BUSIMESSAGE_RESERVED_LENGTH
				+ IUuahBusiMessage.UUAH_BUSIMESSAGE_TRANSACTIONID_LENGTH
				+ IUuahBusiMessage.UUAH_BUSIMESSAGE_TYPE_LENGTH;
		if ((buffer.limit() - buffer.position()) >= minLength) {// ��Ϣͷ
			return true;
		}
		logger.warn("���յ���ݳ���С����С����!");
		return false;
	}

	public static boolean simpleValidateMatchMessageFormat(IoBuffer ioBuffer) {
		return true;
	}

	/**
	 * ����
	 *
	 * @param ioBuffer
	 * @return
	 * @throws Exception
	 */
	public static IUuahBusiMessageCollection getValidUuahBusiMessageCollection(
			IoBuffer in, CharsetDecoder charsetdecoder) throws Exception {
		IUuahBusiMessageCollection uuahBusiMessageCollection = new UuuahBusiMessageCollection();
		IUuahBusiMessage uuahBusiMessage;
		int position = in.position();

		byte[] buffer = in.array();
		byte[] temp;
		buffer = ArrayUtils.subarray(buffer, 0, in.limit());
		while (in.hasRemaining()) {
			if (!validateUuahBusiMessage(in)) {
				break;
			}
			uuahBusiMessage = new UuahBusiMessage();
			temp = ArrayUtils.subarray(buffer, position, position
					+ IUuahBusiMessage.UUAH_BUSI_MESSAGE_BASICVER_LENGTH);
			int basicVer = UuahUtils.byteArraytoInt(temp);
			// �����Ч���ж�
			if (basicVer > 1024 || basicVer <= 0) {
				logger.warn("���յ�basicVer>1024��<=0,��Ϊ��Ч���!");
				in.position(in.limit());
				break;
			}

			position += IUuahBusiMessage.UUAH_BUSI_MESSAGE_BASICVER_LENGTH;

			temp = ArrayUtils.subarray(buffer, position, position
					+ IUuahBusiMessage.UUAH_BUSI_MESSAGE_LENGTH_LENGTH);
			int length = UuahUtils.byteArraytoInt(temp);
			// �����Ч���ж�
			if (length > 8096 || length <= 0) {
				logger.warn("���յ���ݳ���>8096��<=0,��Ϊ��Ч���!");
				in.position(in.limit());
				break;
			}
			position += IUuahBusiMessage.UUAH_BUSI_MESSAGE_LENGTH_LENGTH;

			if ((in.limit() - in.position()) >= length) {
				temp = ArrayUtils
						.subarray(
								buffer,
								position,
								position
										+ IUuahBusiMessage.UUAH_BUSIMESSAGE_TRANSACTIONID_LENGTH);
				String transactionId = UUID.getUUIDString(temp);
				position += IUuahBusiMessage.UUAH_BUSIMESSAGE_TRANSACTIONID_LENGTH;
				temp = ArrayUtils.subarray(buffer, position, position
						+ IUuahBusiMessage.UUAH_BUSIMESSAGE_TYPE_LENGTH);
				int type = UuahUtils.byteArraytoInt(temp);
				position += IUuahBusiMessage.UUAH_BUSIMESSAGE_TYPE_LENGTH;
				temp = ArrayUtils.subarray(buffer, position, position
						+ IUuahBusiMessage.UUAH_BUSIMESSAGE_RESERVED_LENGTH);
				String reserved = new String(temp, charsetdecoder.charset()
						.name());
				position += IUuahBusiMessage.UUAH_BUSIMESSAGE_RESERVED_LENGTH;
				temp = ArrayUtils.subarray(buffer, position, position
						+ IUuahBusiMessage.UUAH_BUSIMESSAGE_CODE_LENGTH);
				int code = UuahUtils.byteArraytoInt(temp);
				position += IUuahBusiMessage.UUAH_BUSIMESSAGE_CODE_LENGTH;
				temp = ArrayUtils.subarray(buffer, position, position
						+ IUuahBusiMessage.UUAH_BUSIMESSAGE_DATALENGTH_LENGTH);
				int dataLength = UuahUtils.byteArraytoInt(temp);
				// �����Ч�Լ��ж�
				if (dataLength > length) {
					in.position(in.limit());
					break;
				}
				position += IUuahBusiMessage.UUAH_BUSIMESSAGE_DATALENGTH_LENGTH;
				byte[] uuahBusiMessageBody = ArrayUtils.subarray(buffer,
						position, position + dataLength);
				position += dataLength;
				uuahBusiMessage.setBasicVer(basicVer);
				uuahBusiMessage.setLength(length);
				uuahBusiMessage.setTransactionId(transactionId);
				uuahBusiMessage.setType(type);
				uuahBusiMessage.setReserved(reserved);
				uuahBusiMessage.setCode(code);
				uuahBusiMessage.setDataLength(dataLength);
				uuahBusiMessage.setUuahBusiMessageBody(uuahBusiMessageBody);
				uuahBusiMessageCollection.addMessage(uuahBusiMessage);

				in.position(position);
			} else {
				break;
			}
		}

		return uuahBusiMessageCollection;
	}

	public static UuahBusiMessage decodeUuahBusiMessage(byte[] data) {
		UuahBusiMessage uuahBusiMessage = new UuahBusiMessage();
		int position = 0;
		byte[] temp = ArrayUtils.subarray(data, position, position
				+ IUuahBusiMessage.UUAH_BUSI_MESSAGE_BASICVER_LENGTH);
		int basicVer = UuahUtils.byteArraytoInt(temp);
		// �����Ч���ж�
		if (basicVer > 1024 || basicVer <= 0) {
			logger.warn("���յ�basicVer>8096��<=0,��Ϊ��Ч���!");
			return uuahBusiMessage;
		}
		position += IUuahBusiMessage.UUAH_BUSI_MESSAGE_BASICVER_LENGTH;

		temp = ArrayUtils.subarray(data, position, position
				+ IUuahBusiMessage.UUAH_BUSI_MESSAGE_LENGTH_LENGTH);
		int length = UuahUtils.byteArraytoInt(temp);
		// �����Ч���ж�
		if (length > 8096 || length <= 0) {
			logger.warn("���յ���ݳ���>8096��<=0,��Ϊ��Ч���!");
			return uuahBusiMessage;
		}
		position += IUuahBusiMessage.UUAH_BUSI_MESSAGE_LENGTH_LENGTH;

		if (data.length >= length) {
			temp = ArrayUtils.subarray(data, position, position
					+ IUuahBusiMessage.UUAH_BUSIMESSAGE_TRANSACTIONID_LENGTH);
			String transactionId = UUID.getUUIDString(temp);
			position += IUuahBusiMessage.UUAH_BUSIMESSAGE_TRANSACTIONID_LENGTH;
			temp = ArrayUtils.subarray(data, position, position
					+ IUuahBusiMessage.UUAH_BUSIMESSAGE_TYPE_LENGTH);
			int type = UuahUtils.byteArraytoInt(temp);
			position += IUuahBusiMessage.UUAH_BUSIMESSAGE_TYPE_LENGTH;
			temp = ArrayUtils.subarray(data, position, position
					+ IUuahBusiMessage.UUAH_BUSIMESSAGE_RESERVED_LENGTH);
			String reserved = null;
			try {
				reserved = new String(temp, "UTF-8");
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			position += IUuahBusiMessage.UUAH_BUSIMESSAGE_RESERVED_LENGTH;
			temp = ArrayUtils.subarray(data, position, position
					+ IUuahBusiMessage.UUAH_BUSIMESSAGE_CODE_LENGTH);
			int code = UuahUtils.byteArraytoInt(temp);
			position += IUuahBusiMessage.UUAH_BUSIMESSAGE_CODE_LENGTH;
			temp = ArrayUtils.subarray(data, position, position
					+ IUuahBusiMessage.UUAH_BUSIMESSAGE_DATALENGTH_LENGTH);
			int dataLength = UuahUtils.byteArraytoInt(temp);
			// �����Ч�Լ��ж�
			if (dataLength > length) {
				return uuahBusiMessage;
			}
			position += IUuahBusiMessage.UUAH_BUSIMESSAGE_DATALENGTH_LENGTH;
			byte[] uuahBusiMessageBody = ArrayUtils.subarray(data, position,
					position + dataLength);
			position += dataLength;
			uuahBusiMessage.setBasicVer(basicVer);
			uuahBusiMessage.setLength(length);
			uuahBusiMessage.setTransactionId(transactionId);
			uuahBusiMessage.setType(type);
			uuahBusiMessage.setReserved(reserved);
			uuahBusiMessage.setCode(code);
			uuahBusiMessage.setDataLength(dataLength);
			uuahBusiMessage.setUuahBusiMessageBody(uuahBusiMessageBody);

			return uuahBusiMessage;
		}
		return uuahBusiMessage;
	}

	public static byte[] encodeUuahBusiMessage(IUuahBusiMessage uuahBusiMessage)
			throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		out.write(new byte[] { (byte) uuahBusiMessage.getBasicVer() });
		out.write(UuahUtils.integer2ByteArray(uuahBusiMessage.getLength(),
				IUuahBusiMessage.UUAH_BUSI_MESSAGE_LENGTH_LENGTH));
		out.write(UUID.getUUIDByteArray(uuahBusiMessage.getTransactionId()));
		out.write(new byte[] { (byte) uuahBusiMessage.getType() });
		out.write(uuahBusiMessage.getReserved().getBytes(
				UuahServer.getUuahContext().getConfiguration()
						.getDefaultEncoding()));
		out.write(UuahUtils.integer2ByteArray(uuahBusiMessage.getCode(),
				IUuahBusiMessage.UUAH_BUSIMESSAGE_CODE_LENGTH));
		out.write(UuahUtils.integer2ByteArray(uuahBusiMessage.getDataLength(),
				IUuahBusiMessage.UUAH_BUSIMESSAGE_DATALENGTH_LENGTH));
		if (uuahBusiMessage.getUuahBusiMessageBody() != null) {
			out.write(uuahBusiMessage.getUuahBusiMessageBody());
		}
		// TODO �ݷ�����
		if (UuahServer.getServerStats() != null) {
			UuahServer.getServerStats().addBusiStats(uuahBusiMessage.getCode());
		}
		return out.toByteArray();
	}
}
